/* ****************************************************************************
 *
 * Copyright (c) Microsoft Corporation. 
 *
 * This source code is subject to terms and conditions of the Microsoft Public License. A 
 * copy of the license can be found in the License.html file at the root of this distribution. If 
 * you cannot locate the  Microsoft Public License, please send an email to 
 * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
 * by the terms of the Microsoft Public License.
 *
 * You must not remove this notice, or any other, from this software.
 *
 * THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
 * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
 * PARTICULAR PURPOSE.
 * ***************************************************************************/




#if !defined(AFX_PGLOBJECTMANAGER_H__6BC55A62_1D34_49EE_B5DE_371EC2DB9E01__INCLUDED_)
#define AFX_PGLOBJECTMANAGER_H__6BC55A62_1D34_49EE_B5DE_371EC2DB9E01__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000


class CPGLObject;
class CPGLLegend;
class CPGLRegion;

template<class Object>
class TObjectPtrContainer : public pgl::THasParent<CPGLRegion>
{
public:
	//! Pointer container
	typedef boost::shared_ptr<Object> ObjectPtr;
	typedef std::list<ObjectPtr> Container;

	TObjectPtrContainer(){};
	TObjectPtrContainer( const TObjectPtrContainer<Object>& objects ){	*this = objects;};
	TObjectPtrContainer& operator=( const TObjectPtrContainer<Object>& objects )
	{	if (this != &objects)
		{	m_objects = objects.m_objects; };
		return *this;
	};
	~TObjectPtrContainer()
	{
		Clear();
	};

	bool IsEmpty() const	{	return m_objects.size()==0;};
	//! return true if layer empty
	bool IsEmptyLayer(gfxinterface::CGfxInterface& gfx);
	//! returns true if in manager
	bool IsIn(long uID) const;
	//! AddHead
	void AddHead(ObjectPtr pObject)											{ PushFront(pObject);};
	void PushFront(ObjectPtr pObject);
	//! AddTail
	void AddTail(ObjectPtr pObject)											{ PushBack(pObject);};
	void PushBack(ObjectPtr pObject);
	//! returns object count
	size_t GetCount( ) const												{ return m_objects.size();};
	//! begin of list
	typename Container::iterator begin()									{ return m_objects.begin();};
	//! begin of list, const
	typename Container::const_iterator begin() const						{ return m_objects.begin();};
	//! begin of list
	typename Container::iterator end()										{ return m_objects.end();};
	//! begin of list, const
	typename Container::const_iterator end() const							{ return m_objects.end();};
	//! return object at index i
	ObjectPtr operator [] (size_t i);
	//! make sure there only 1 entry for each object
	void Unique()															{ m_objects.unique();};
	//@}

	//! \name Remove Methods
	//@{
	//! delete and removes the pointer pObject
	void RemoveObject(ObjectPtr pObject);
	//! removes the pointer to object with Id number = ID
	void RemoveObject(long ID);
	//! deleting objects in list and emptying it
	void Clear();
	//@}


	//! Plots object in manager
	void PlotGfx(gfxinterface::CGfxInterface& gfx);

protected:
	Container m_objects;
};

template<class Object>
bool  TObjectPtrContainer<Object>::IsEmptyLayer(gfxinterface::CGfxInterface& gfx)
{
	if (m_objects.empty())
		return true;

	Container::iterator it;
	ObjectPtr pObject;

	for (it=m_objects.begin();it!=m_objects.end();it++)
	{
		pObject=*it;

		if (pObject->IsVisible() && pObject->IsInLayer(gfx.GetLayer()))
			return false;
	}

	return true;
}

template<class Object>
typename TObjectPtrContainer<Object>::ObjectPtr  TObjectPtrContainer<Object>::operator [] (size_t i)
{
	if (i<0 || i>=m_objects.size())
		return ObjectPtr();

	size_t icur=0;
	Container::iterator it=m_objects.begin();
	while ( icur != i && it != m_objects.end() )
	{	++it; ++icur;};

	if (it == m_objects.end() )
		return ObjectPtr();
	else
		return *it;
}

template<class Object>
void TObjectPtrContainer<Object>::PushFront(ObjectPtr pObject)										
{ 
	if (pObject)
		m_objects.push_front(pObject);
};

template<class Object>
void TObjectPtrContainer<Object>::PushBack(ObjectPtr pObject)
{ 
	if (pObject)
		m_objects.push_back(pObject);
};

template<class Object>
void TObjectPtrContainer<Object>::Clear()
{
	m_objects.clear();
};

template<class Object>
bool TObjectPtrContainer<Object>::IsIn(long uID) const
{
	Container::const_iterator it;
	// object List
	for (it = m_objects.begin(); it != m_objects.end(); ++it)
	{
		// testing if object.ID == uID
		if ((*it)->CheckID(uID))
			return true;
	}
	return false;
};

template<class Object>
void TObjectPtrContainer<Object>::RemoveObject(ObjectPtr pObject)
{
	if (!pObject)
		return;

	Container::iterator it;
		
	// testing if pObject is in _objectList
	it = std::find(m_objects.begin(), m_objects.end(), pObject);
	if (it != m_objects.end())
	{
		// pObject is in _objectList at position pos
		// removing from list
		m_objects.erase(it);
	}
};

template<class Object>
void TObjectPtrContainer<Object>::RemoveObject(long ID)
{
	Container::iterator it;
	// object List
	for (it = m_objects.begin(); it != m_objects.end(); ++it)
	{
		// testing if object.ID == ID
		if ((*it)->CheckID(ID))
		{
			// pObject is in _objectList at position pos
			// removing from list
			m_objects.erase(it);
			// work is finished
			return;
		}
	}
};


template<class Object>
void TObjectPtrContainer<Object>::PlotGfx(gfxinterface::CGfxInterface &gfx)
{
	Container::iterator it;
	for (it=m_objects.begin();it!=m_objects.end();++it)
	{
		(*it)->PlotGfx(gfx);
	}
};

/*! 
	\defgroup PGLManagerGroup Manager and containers.
	\ingroup PGLCoreGroup
*/

/*! \brief An object container - manager

\ingroup PGLManagerGroup
*/
class PGLCORE_EXT_CLASS CPGLObjectManager : public TObjectPtrContainer< CPGLObject >
{
public:
	typedef boost::shared_ptr<CPGLLegend> LegendPtr;
	//! \name Legend
	//@{
	//! add object to legend
	void PushLinesTop(LegendPtr pLegend);
	//@}

	//! \name Serialization and debugging
	//@{
	//! Serialization
	virtual void SerializeXML(CPGLArchive& ar);
	//@}
};

#endif // !defined(AFX_PGLOBJECTMANAGER_H__6BC55A62_1D34_49EE_B5DE_371EC2DB9E01__INCLUDED_)
